﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Data;
using System.Xml;
using SdmxMl.SmsImportCfg;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;
using SdmxMl.GenericMetadata;


namespace SdmxMl.SmsImportCfg
{
    public class SakeQuest
    {
        private SmManager sm = null;
        private MetadataSetType metaSet = null;
        private MetadataStructureDefinitionType msd = null;
        private ReportStructureType report = null;
        private ExcelDataReader.ExcelDataReader spreadsheetQuest = null;
        string[] subsetLang = { "de", "fr" };
        private int blocSize;

        public SakeQuest()
        {
            sm = ReferenceManager.GetSmContainerImage();
            blocSize = 16;
        }

        public void ParseQuestFile(string path)
        {
            // Create SDMX questions container
            CreateMetaSetArtefact();

            //Get excel content
            spreadsheetQuest = LoadSources(path);

            ScanRows();

            NavigationManager.LoadFromSmManager(sm);


        }

        private ExcelDataReader.ExcelDataReader LoadSources(string propertyPath)
        {
            ExcelDataReader.ExcelDataReader spreadsheet = null;
            if (propertyPath == null)
                throw new ApplicationException("Please provides path.");

            FileStream fs = null;
            try
            {
                fs = new FileStream(propertyPath, FileMode.Open, FileAccess.Read, FileShare.Read);
                spreadsheet = new ExcelDataReader.ExcelDataReader(fs);
            }
            finally
            {
                if (fs != null)
                    fs.Close();
            }

            return spreadsheet;
        }


        private void CreateMetaSetArtefact()
        {
            // Fetch MSD and report for SAKE quest
            msd = sm.GetArtefact(SdmxArtefactType.MetadataStructureDefinitions,
                new ArtefactRefBase("CH1_SILC+MD_SILC_CATI_QUEST+1.0"), true) as MetadataStructureDefinitionType;
            report = msd.ReportStructureList.LocateItem("R_SAKE");

            // Create generic metadataset to hold questions
            metaSet = new MetadataSetType();

            metaSet.Id = "MS_Q_CH_MOD";
            metaSet.AgencyId = "CH1_SAKE";
            metaSet.Version = "2013.0";
       //     metaSet.Name.UpdateDefaultText("Questionnaire (MODUL ARBEITSUNFÄLLE UND SONSTIGE BERUFSBEDINGTE GESUNDHEITSPROBLEME)");
            metaSet.Name.UpdateDefaultText("Questionnaire (MODUL UNBEZAHLTE ARBEIT UND FAMILIENERGÄNZENDE KINDERBETREUUNG)");

            // Refered MSD FullId
            metaSet.MetadataStructureRef.Id = msd.Id;
            metaSet.MetadataStructureRef.AgencyId = msd.AgencyId;
            metaSet.MetadataStructureRef.Version = msd.Version;

            // Refered report
            metaSet.ReportRef = report.Id;

            sm.PutArtefact(SdmxArtefactType.MetadataSet, metaSet);
        }

        private void FillQuestRow(string varId, MultiLang quest, MultiLang infoInt, CodeListType clt, CodeListType cltQuality )
        {
            // Now MetaSet
            AttributeValueSetType at = new AttributeValueSetType(msd, report, metaSet);

            // The target values
            at.TargetValuesTypeList.SetComponentValue("QUEST_TYPE", "E");
            at.TargetValuesTypeList.SetComponentValue("YEAR", "2013");
            at.TargetValuesTypeList.SetComponentValue("VARNAME", varId);


            // The reported attributes
            SetRepAttValue(at, "QUESTION", quest);
            SetRepAttValue(at, "INFO_INT", infoInt);
            if (clt != null)
            {
                SetRepAttValue(at, "CODELIST_URN", new MultiLang(UrnManager.FullIdToUrn(clt.ArType, clt.FullIdent)));
            }
            if (cltQuality != null)
            {
                SetRepAttValue(at, "QUALITY_URN", new MultiLang(UrnManager.FullIdToUrn(cltQuality.ArType, cltQuality.FullIdent)));
            }

//            SetRepAttValue(at, "INFO_INT", new MultiLang(vh.domains));
            metaSet.AttributeValueSetList.Add(at);
        }

        private void SetRepAttValue(AttributeValueSetType at, string conceptId, MultiLang ml)
        {
            ReportedAttributeType ra = at.ReportedAttributeList.GetReportedAttributeOfConcept(conceptId);
            if (ra != null)
                ra.Value = ml == null ? new MultiLang() : ml;
        }


        private void ScanRows()
        {
            string[] qlines = new string[blocSize];
            DataTable dt = spreadsheetQuest.WorkbookData.Tables["EFG2013-CATI-F"];
            WorkSheetHelper whFr = new WorkSheetHelper(dt);

            //dt = spreadsheetQuest.WorkbookData.Tables["CH-Mod_2013_E"];
            //WorkSheetHelper whEn = new WorkSheetHelper(dt);

            dt = spreadsheetQuest.WorkbookData.Tables["EFG2013-CATI-D"];
            WorkSheetHelper whDe = new WorkSheetHelper(dt);

            dt = spreadsheetQuest.WorkbookData.Tables["EFG2013-CATI-I"];
            WorkSheetHelper whIt = new WorkSheetHelper(dt);

            CodeListType clt = null;
            CodeListType cltQuality = null;


            int row = 1;
            while (row < dt.Rows.Count)
            {
                SakeScanQuestion sqDe = null;
                try
                {
                    SakeScanQuestion sqFr = new SakeScanQuestion(row, whFr, "fr", blocSize);
                    sqDe = new SakeScanQuestion(row, whDe, "de", blocSize);
                    SakeScanQuestion sqIt = new SakeScanQuestion(row, whIt, "it", blocSize);
                  //  SakeScanQuestion sqEn = new SakeScanQuestion(row, whEn, "en");

                    MultiLang qt = new MultiLang();
                    qt.UpdateForLanguage("de", sqDe.Question);
                    qt.UpdateForLanguage("it", sqIt.Question);
                    qt.UpdateForLanguage("fr", sqFr.Question);
              //      qt.UpdateForLanguage("en", sqEn.Question);

                    MultiLang infoInt = new MultiLang();
                    infoInt.UpdateForLanguage("de", sqDe.InfoInt);
                    infoInt.UpdateForLanguage("it", sqIt.InfoInt);
                    infoInt.UpdateForLanguage("fr", sqFr.InfoInt);
              //      infoInt.UpdateForLanguage("en", sqEn.InfoInt);

                    // Codelist ?
                    cltQuality = clt = null;
                    //if (clt != null && sqDe.Clt != null && sqDe.Clt.CodeList.Count > 1)
                    //{
                    //    foreach (CodeType c in sqDe.Clt.CodeList)
                    //    {
                    //        MergeCodeLang(c, sqDe, sqFr);
                    //        MergeCodeLang(c, sqDe, sqIt);
                    //        MergeCodeLang(c, sqDe, sqEn);
                    //    }

                    //    clt = CodelistAlreadyDefined(sqDe.Clt);
                    //    if (clt != null)
                    //        clt.Name.UpdateDefaultText(clt.Name.ToString() + ", " + sqDe.QuestId);
                    //    else
                    //    {
                    //        clt = sqDe.Clt;
                    //        sm.PutArtefact(SdmxArtefactType.CodeLists, sqDe.Clt);
                    //    }
                    //}

                    //// Quality Codelist ?
                    //if (sqDe.CltQuality != null && sqDe.CltQuality.CodeList.Count > 1)
                    //{
                    //    foreach (CodeType c in sqDe.CltQuality.CodeList)
                    //    {
                    //        MergeQualityCodeLang(c, sqDe, sqFr);
                    //        MergeQualityCodeLang(c, sqDe, sqIt);
                    //        MergeQualityCodeLang(c, sqDe, sqEn);
                    //    }

                    //    cltQuality = CodelistAlreadyDefined(sqDe.CltQuality);
                    //    if (cltQuality != null)
                    //        cltQuality.Name.UpdateDefaultText(cltQuality.Name.ToString() + ", " + sqDe.QuestId);
                    //    else
                    //    {
                    //        cltQuality = sqDe.CltQuality;
                    //        sm.PutArtefact(SdmxArtefactType.CodeLists, cltQuality);
                    //    }
                    //}

                    FillQuestRow(sqFr.QuestId, qt, infoInt, clt, cltQuality);
                    row += blocSize;
                }
                catch (Exception ex)
                {
                    throw new ApplicationException("Quest: " + sqDe.QuestId + Environment.NewLine + ex.Message);
                }
            }
        }

        private void MergeCodeLang(CodeType c, SakeScanQuestion sqDe, SakeScanQuestion sq)
        {
            if (sq.Clt == null)
            {
                sqDe.Clt.Name.UpdateForLanguage(sq.Lang, string.Format("No codelist for {0} in question {1}", sq.Lang, sqDe.QuestId));
                return;
            }
            //    throw new ApplicationException(string.Format("No codelist for {0} in question {1}", sq.Lang, sqDe.QuestId));

            ISdmxHierarchyListItem item = sq.Clt.CodeList.LocateItem(c.Id);
            if (item == null)
            {
                //throw new ApplicationException(string.Format("No code {0} for {2} in question {1}", c.Id, sqDe.QuestId, sq.Lang));
                c.Name.UpdateForLanguage(sq.Lang, string.Format("No code {0} for {2} in question {1}", c.Id, sqDe.QuestId, sq.Lang));
            }
            else
                c.Name.UpdateForLanguage(sq.Lang, item.Name.GetForLanguage(sq.Lang));
        }


        private void MergeQualityCodeLang(CodeType c, SakeScanQuestion sqDe, SakeScanQuestion sq)
        {
            if (sq.CltQuality == null)
            {
                sqDe.CltQuality.Name.UpdateForLanguage(sq.Lang, string.Format("No codelist for {0} in question {1}", sq.Lang, sqDe.QuestId));
                return;
            }
            //    throw new ApplicationException(string.Format("No codelist for {0} in question {1}", sq.Lang, sqDe.QuestId));

            ISdmxHierarchyListItem item = sq.CltQuality.CodeList.LocateItem(c.Id);
            if (item == null)
            {
                //throw new ApplicationException(string.Format("No code {0} for {2} in question {1}", c.Id, sqDe.QuestId, sq.Lang));
                c.Name.UpdateForLanguage(sq.Lang, string.Format("No code {0} for {2} in question {1}", c.Id, sqDe.QuestId, sq.Lang));
            }
            else
                c.Name.UpdateForLanguage(sq.Lang, item.Name.GetForLanguage(sq.Lang));
        }

        private CodeListType CodelistAlreadyDefined(CodeListType newCodelist)
        {
            ArtefactManager amgr = sm.GetArtefactManager(SdmxArtefactType.CodeLists);
            foreach (CodeListType clt in amgr.ArtefactList)
            {
                if (clt.Id == "CL_YES_NO" && newCodelist.CodeList.Count == 2 && newCodelist.CodeList[0].Id == "1")
                {
                    report.TargetId = "TargetId";

                }
                if (SameCodes(newCodelist.CodeList, clt.CodeList))
                    return clt;
            }
            return null;
        }

        private bool SameCodes(CodeList a, CodeList b)
        {

            bool sameCodes = false;
            if (a.Count == b.Count)
            {
                sameCodes = true;
                for (int c = 0; c < a.Count; c++)
                {
                    if (a[c].Id != b[c].Id)
                    {
                        sameCodes = false;
                        break;
                    }
                    else
                    {
                        foreach (string lg in subsetLang)
                        {
                            if (string.Compare(a[c].Name.GetForLanguage(lg).Trim(), b[c].Name.GetForLanguage(lg).Trim(), true) != 0)
                            {
                                sameCodes = false;
                                break;
                            }
                        }
                        if (sameCodes == false)
                            break;
                    }
                }
            }

            return sameCodes;
        }
     

    }
}
